/*
 * @(#)AbstractCacheService.java 2011-11-28
 *
 * Copyright 2011 北龙中网（北京）科技有限责任公司. All rights reserved.
 */
package cn.shangjia.shop.sync.service;

import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import cn.shangjia.common.domain.Domain;
import cn.shangjia.common.util.StringUtils;
import cn.shangjia.shop.dao.AbstractCacheDao;
import cn.shangjia.shop.dao.AbstractCacheDao.CacheType;

/**
 *
 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
 * @version 1.0, 2011-11-28 13:28:12
 * @since 1.0
 */
public class AbstractCacheService<T extends Domain> extends AbstractSyncService<T> implements ApplicationContextAware{
	
	protected AbstractCacheDao<T> dao;
	
	@SuppressWarnings("unchecked")
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		String daoName = getClassName() + "Dao";
		daoName = daoName.substring(0,1).toLowerCase() + daoName.substring(1);
		dao = applicationContext.getBean(daoName,AbstractCacheDao.class);
	}
	
	/**
	 *  此 是业务特殊性 . 商铺服务 是以用户为核心的服务. 
	 *  此判定 是 是否强制 以 userId 为缓存对象主键 为key. 
	 *  默认 不是 . 
	 *  如果 你需要 以userId为主键 . 
	 *  那么应该 重写 该方法 . 并返回 true;
	 * 
	 * @return
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	protected boolean isUserIdKey() {
		return false;
	}
	
	/**
	 *  是否需要更新缓存列表 . 的开关 
	 *  默认为 不更新. 如果 需要更新 列表缓存 
	 *  那么 你应该 重写该方法 打开开关 返回 true
	 * 
	 * @return
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	protected boolean isRemoveListCache() {
		return false;
	}
	
	/**
	 *  是否需要 管理 对象缓存 的 开关 , 
	 *  默认 为打开状态 , 如果 你所关注的表 不需要 管理 对象key-value方式的对象缓存
	 *  那么 你应该 关闭此开关 . 将返回值 改为 false;
	 * 
	 * @return
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	protected boolean isManagerObjectCache() {
		return true;
	}
	
	/**
	 *  可以 更改 po中的属性 到缓存中.
	 *  如果 同步中 你有 需要 将对象中属性的值 进行 更改 再放入缓存的话. 
	 *  那么 你应该 重写 此方法
	 * 
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	protected void repo(T po) {
	}

	/**
	 * 插入操作
	 *  
	 * @param userId
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	@Override
	protected void insert(String id, String userid) {
		if (isManagerObjectCache()) {
			T po = dao.readNoCache(id);
			if (po == null) {
				logger.warn("[" , getClassName() , "-添加操作], 数据库没有数据, 请检查数据源是否正确, id=", id, ", userid=", userid);
			}
			repo(po);
			
			String key = dao.getKey(CacheType.OBJ, isUserIdKey() ? userid : id);
			dao.add(key, po);
		}
		if (isRemoveListCache())
			removeListCache(userid);
	}
	
	/**
	 * 更新操作 
	 * 
	 * @param centerPo
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	@Override
	protected void update(String id, String userid) {
		if (isManagerObjectCache()) {
			T po = dao.readNoCache(id);
			if (po == null) {
				logger.warn("[" , getClassName() , "-更新操作], 数据库没有数据, 请检查数据源是否正确, id=", id, ", userid=", userid);
			}
			repo(po);
			
			String key = dao.getKey(CacheType.OBJ, isUserIdKey() ? userid : id);
			T t = dao.get(key);
			if (t == null) {
				dao.add(key, po);
			} else {
				dao.replace(key, po);
			}
		}
		if (isRemoveListCache())
			removeListCache(userid);
	}

	/**
	 * 软删除 操作 
	 * @param centerPo
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	@Override
	protected void delete(String id, String userid) {
		if (isManagerObjectCache()) {
			String key = dao.getKey(CacheType.OBJ, isUserIdKey() ? userid : id);
			dao.remove(key);
		}
		if (isRemoveListCache())
			removeListCache(userid);
	}
	
	/**
	 *  清除 list类缓存
	 *  
	 *  默认是什么也不做的 . 如果需要做 则 需要重写 开关方法 
	 * 
	 * @param T po
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	private void removeListCache(String userid) {
		
		if (StringUtils.isEmpty(userid))
			return ;
		
		Set<String> keySet = dao.getKeys(userid);
		if (keySet == null || keySet.isEmpty())
			return;
		
		for (String key : keySet) {
			if (!key.startsWith(getClassName()) || !key.endsWith(userid))
				continue; //判断 是否 是该表数据 以及验证 散列主键的有效性
			try {
				dao.remove(key); //清理掉缓存中的列表
				dao.delKeys(userid, key); //清理掉keys中的key 防止不必要的轮询
			} catch(Exception e) {
				logger.warn("[商铺同步] - 更新列表or条目缓存失败 id = ", userid , ", key = " , key);
			}
		}
	}
	
}
